﻿#region Copyright and License
/*==============================================================================
 *  Copyright (c) cndotnet.org Corporation.  All rights reserved.
 * ===============================================================================
 * This code and information is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the implied warranties
 * of merchantability and fitness for a particular purpose.
 * ===============================================================================
 * Licensed under the GNU General Public License (GPL) v2
 * http://www.cndotnet.org/ucenter
 * ==============================================================================*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data.Linq;
using UCenter.DataProvider;
using UCenter.Models;
using UCenter.BusinessContract;
using UCenter.Core.Service;
using UCenter.Core.Security;
using UCenter.Core.Common;
using UCenter.EmailService;
using UCenter.TemplateEngine;
using UCenter.ServiceContract;
using UCenter.BusinessContract.Enumeration;

namespace UCenter.Services {
    public class AccountService : ServiceBase, IAccountService
    {
        public bool Register(AccountContract account) 
        {
            // Create a user instance
            User user = new User {
                Password = CryptographyManager.EncodePassowrd(account.Password),
                Email = account.Email,
                CreateDate = DateTime.Now,
                IsOnline = false,
                Status = (int)MembershipStatus.NotVerified
            };

            Profile profile = new Profile {
                TrueName = account.TrueName
            };
            user.Profile = profile;

            IFriendGroupService groupService = LoadService<IFriendGroupService>();
            foreach (var item in groupService.GetDefaultGroups())
            {
                user.FriendGroups.Add(new FriendGroup { GroupName = item.GroupName });
            }

            // Create a verify code instacne
            VerifyCode code = new VerifyCode {
                CodeType = 1,
                Code = Guid.NewGuid().ToString(),
                CreateDate = DateTime.Now,
                SendDate = DateTime.Now,
                ExpireDate = DateTime.Now.AddDays(30)
            };
            user.VerifyCodes.Add(code);

            // Send a verify email
            TemplateContract template = new TemplateContract("RegisterTemplate");
            template.Parameters.Add("Name", account.TrueName);
            template.Parameters.Add("URL", String.Format("http://www.ucenter.com/Account/RegVerify/{0}", code.Code));
            template.Parameters.Add("Team", "UCenter.NET Team");


            MailContract mail = new MailContract {
                Category = MailCategory.Register,
                Content = template,
                CreateDate = DateTime.Now,
                FromAddress = AppSettings.FromEmailAddress,
                Recipient = account.Email,
                Retries = 5,
                Subject = "Welcome to register UCenter.NET",
                Priority = MailPriority.Higher
            };

            MailService mailService = new MailService();
            mailService.Send(mail);

            LoadRepository<IAccountRepository>().InsertUser(user);

            return true;
        }
       
        internal static AccountContract GetAccount(User user, bool delayLoad) 
        {
            if (user == null) {
                return null;
            }
            AccountContract account = new AccountContract();
            account.ID = user.ID;
            account.Email = user.Email;
            account.Status = (MembershipStatus)user.Status;
            account.CreateDate = user.CreateDate;
            account.Password = user.Password;
            if (!delayLoad) {
                account.TrueName = user.Profile.TrueName;
                account.QQ = user.Profile.QQ;
                account.MSN = user.Profile.MSN;

                account.NickName = user.Profile.NickName;
                account.PhoneNumber = user.Profile.PhoneNumber;
                account.Hometown = user.Profile.Hometown;
                account.Birthday = user.Profile.Birthday;
                account.Website = user.Profile.Website;
                account.StatusSetting = user.Profile.State;
                account.UpdateStatusTime = user.Profile.StateRefreshTime;
                if (string.IsNullOrEmpty(user.Profile.Avatar)) {
                    account.LogoUrl = "/Themes/Standard/Images/120_0_0.gif";
                }
                else {
                    account.LogoUrl = user.Profile.Avatar;
                }
            }
            return account;
        }

        public MembershipStatus ValidateUser(string email, string password) 
        {
            var account = GetAccountByEmail(email, true);

            if (account == null) {
                return MembershipStatus.Failed;
            }

            string passwordEncoded = CryptographyManager.EncodePassowrd(password);
            if (passwordEncoded != account.Password) {
                return MembershipStatus.Failed;
            }

            int status = ((int)account.Status);

            if (status == 3) {
                return MembershipStatus.Locked;
            }

            if (status != 4) {
                return MembershipStatus.NotVerified;
            }

            return MembershipStatus.Success;
        }

        public MembershipStatus ValidateUser(string email) {
            MembershipStatus result = MembershipStatus.Success;

            if (GetAccountByEmail(email, true) == null) {
                result = MembershipStatus.Failed;
            }

            return result;
        }

        public bool ValidatePassword(string password) {
            var user = GetAccountByEmail(ContextService.Current.User.Email, true);

            if (user != null) {
                string passwordEncoded = CryptographyManager.EncodePassowrd(password);
                if (passwordEncoded == user.Password) {
                    return true;
                }
            }

            return false;
        }

        public bool ChangePassword(string oldPassword, string newPassword) {
            string oldPasswordEncoded = CryptographyManager.EncodePassowrd(oldPassword);
            string newPasswordEncoded = CryptographyManager.EncodePassowrd(newPassword);

            return LoadRepository<IAccountRepository>().ChangePassword(ContextService.Current.User.Email, oldPasswordEncoded, newPasswordEncoded);
        }

        public bool ResetPassword(string email) {
            bool result = false;

            if (MembershipStatus.Success == ValidateUser(email)) {
                AccountContract account = GetAccountByEmail(email, true);

                TemplateContract template = new TemplateContract("ResetPasswordTemplate");
                template.Parameters.Add("Name", account.TrueName);
                template.Parameters.Add("Password", account.Password);
                template.Parameters.Add("URL", String.Format("http://www.ucenter.com/Account/ResetPassword/"));
                template.Parameters.Add("MailDate", DateTime.Now.ToString());

                MailContract mail = new MailContract {
                    Category = MailCategory.ResetPassword,
                    Content = template,
                    CreateDate = DateTime.Now,
                    FromAddress = AppSettings.FromEmailAddress,
                    Recipient = email,
                    Retries = 5,
                    Subject = "Get your UCenter password back.",
                    Priority = MailPriority.Higher
                };

                MailService service = new MailService();
                service.Send(mail);

                result = true;
            }

            return result;
        }

        public bool Exist(string email) {
            bool result = false;

            if (GetAccountByEmail(email, true) != null) {
                result = true;
            }

            return result;
        }

        /// <summary>
        /// update user's online info
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="online"></param>
        public void UpdateOnlie(int userID, bool online) {
            LoadRepository<IAccountRepository>().UpdateOnline(userID, online);
        }

        public void SetStatus(int userID, string status) {
            LoadRepository<IAccountRepository>().SetStatus(userID, status);
        }

        public void UpdateUserLogo(int userID, string userLogo) {
            LoadRepository<IAccountRepository>().UpdateUserLogo(userID, userLogo);
        }

        public void UpdateProfile(AccountContract user) {
            Profile p = new Profile();
            p.Birthday = user.Birthday;
            p.Gender = user.Gender;
            p.Hometown = user.Hometown;
            p.ID = user.ID;
            p.MSN = user.MSN;
            p.NickName = user.NickName;
            p.PhoneNumber = user.PhoneNumber;
            p.QQ = user.QQ;
            p.State = user.StatusSetting;
            p.TrueName = user.TrueName;
            p.StateRefreshTime = user.UpdateStatusTime;
            p.Avatar = user.LogoUrl;
            p.Website = user.Website;
            LoadRepository<IAccountRepository>().UpdateProfile(p);
        }

        #region IAccountService Members

        public AccountContract GetAccountByEmail(string email, bool delayLoad) {
            DataLoadOptions loadOptions = null;
            if (!delayLoad) {
                loadOptions = new DataLoadOptions();
                loadOptions.LoadWith<User>(u => u.Profile);
                loadOptions.LoadWith<User>(u => u.Friendships);
            }
            User user = LoadRepository<IAccountRepository>().GetSingle("Email==@0", loadOptions, email);
            AccountContract account = GetAccount(user, delayLoad);
            return account;
        }

        public List<AccountContract> GetAccountsByName(string name, bool delayLoad) {
            List<AccountContract> accounts = new List<AccountContract>();
            DataLoadOptions loadOptions = null;
            if (!delayLoad) {
                loadOptions = new DataLoadOptions();
                loadOptions.LoadWith<User>(u => u.Profile);
                loadOptions.LoadWith<User>(u => u.Friendships);
            }
            var users = LoadRepository<IAccountRepository>().GetList("Profile.TrueName.Contains(@0)", loadOptions, name);
            foreach (var u in users) {
                accounts.Add(GetAccount(u, false));
            }
            return accounts;
        }

        public AccountContract GetAccountByID(int id,bool loadAll) {
            DataLoadOptions loadOptions = new DataLoadOptions();
            if (loadAll) {
                loadOptions.LoadWith<User>(u => u.Profile);
                loadOptions.LoadWith<User>(u => u.Friendships);
            }
            User user = LoadRepository<IAccountRepository>().GetSingle("ID==@0",loadOptions,id);
            AccountContract account = GetAccount(user, false);
            return account;
        }

        public List<AccountContract> GetAccountsByContracts(int userID, ContractTypeEnum contractType, List<string> contracts) {
            List<AccountContract> accounts = new List<AccountContract>();
            DataLoadOptions loadOptions = null;
            loadOptions = new DataLoadOptions();
            loadOptions.LoadWith<User>(u => u.Profile);
            loadOptions.LoadWith<User>(u => u.Friendships);
            StringBuilder sb = new StringBuilder();
            string field = "Profile.MSN";
            if (contractType == ContractTypeEnum.QQ) {
                field = "Profile.QQ";
            }
            else if (contractType == ContractTypeEnum.Email) {
                field = "Email";
            }
            int i = 1;
            sb.Append("(");
            foreach (string s in contracts) {
                sb.Append(field + "==@" + i);
                if (i < contracts.Count) {
                    sb.Append(" OR ");
                }
                i++;
            }
            sb.Append(")");
            List<Object> list = new List<object>();
            list.Add(userID);
            foreach (string s in contracts) {
                list.Add(s);
            }
            var users = LoadRepository<IAccountRepository>().GetList("ID!=@0 and " + sb.ToString(), loadOptions, list.ToArray());
            foreach (var u in users) {
                accounts.Add(GetAccount(u, false));
            }
            return accounts;
        }
        #endregion
    }
}
